//
// rm.h
//
//   Record Manager component interface
//
// This file does not include the interface for the RID class.  This is
// found in rm_rid.h
//

#ifndef RM_H
#define RM_H

// Please DO NOT include any files other than redbase.h and pf.h in this
// file.  When you submit your code, the test program will be compiled
// with your rm.h and your redbase.h, along with the standard pf.h that
// was given to you.  Your rm.h, your redbase.h, and the standard pf.h
// should therefore be self-contained (i.e., should not depend upon
// declarations in any other file).

// Do not change the following includes
#include "redbase.h"
#include "rm_rid.h"
#include "pf.h"

//
// RM_FileHdr: Header structure for files
//
struct RM_FileHdr
{
    int firstFree;      // first free page in the linked list
    int numPages;       // # of pages in the file
    int extRecordSize;  // record size as seen by users
};

// RM_Record: RM Record interface
//
class RM_Record {
private:
    int recordSize;
    char * data;
    RID rid;
public:
    RM_Record ();
    ~RM_Record();

    // Return the data corresponding to the record.  Sets *pData to the
    // record contents.
    RC GetData(char *&pData) const;

    // Return the RID associated with the record
    RC GetRid (RID &rid) const;

    RC Set(char *pData, int size, RID rid_);
};

//
// RM_FileHandle: RM File interface
//
class RM_FileHandle {
    friend class RM_FileScan;
    friend class RM_Manager;
private:
    RM_FileHdr hdr;

    PF_FileHandle *pfHandle;
    bool bFileOpen;    // open flag for file
    bool bHdrChanged;  // dirty flag for FileHeader

    RC SetFileHeader(PF_PageHandle ph) const;

    bool IsValidRID(const RID rid) const;

    // persist header into the first page of a file for later
    RC GetFileHeader(PF_PageHandle ph);
    RC GetSlotPointer(PF_PageHandle ph, SlotNum s, char *& pData) const;
    RC GetNextFreePage(PageNum& pageNum);
    RC GetNextFreeSlot(PF_PageHandle& ph, PageNum& pageNum, SlotNum&);
public:
    RM_FileHandle ():pfHandle(NULL), bFileOpen(0), bHdrChanged(0){}
    ~RM_FileHandle();
    RC Open(PF_FileHandle* pfh, int recordSize);
    RC SetHdr(RM_FileHdr h);

    // Given a RID, return the record
    RC GetRec     (const RID &rid, RM_Record &rec) const;

    RC InsertRec  (const char *pData, RID &rid);       // Insert a new record
    RC DeleteRec  (const RID &rid);                    // Delete a record
    RC UpdateRec  (const RM_Record &rec);              // Update a record

    // Forces a page (along with any contents stored in this class)
    // from the buffer pool to disk.  Default value forces all pages.
    RC ForcePages (PageNum pageNum = ALL_PAGES);

    bool hdrChanged() const;
    PageNum GetNumPages() const;
    SlotNum GetNumSlots() const;

    RC IsValid() const;
};

//
// RM_FileScan: condition-based scan of records in the file
//
class RM_FileScan {
private:
    Predicate *pred;
    RM_FileHandle *prmh;
    RID current;
    bool bOpen;
public:
    RM_FileScan  ();
    ~RM_FileScan ();

    RC OpenScan  (const RM_FileHandle &fileHandle,
                  AttrType   attrType,
                  int        attrLength,
                  int        attrOffset,
                  CompOp     compOp,
                  void       *value,
                  ClientHint pinHint = NO_HINT); // Initialize a file scan
    RC GetNextRec(RM_Record &rec);               // Get next matching record
    RC CloseScan ();                             // Close the scan
    RC GotoPage(PageNum p);
    
    bool IsOpen() const { return (bOpen && prmh!=NULL && pred!=NULL);}
    void resetState() { current=RID(1,-1); }
    int GetNumSlotsPerPage() const { return prmh->GetNumSlots(); }
};

//
// RM_Manager: provides RM file management
//
class RM_Manager {
private:
    PF_Manager&   pfm; // A reference to the external PF_Manager
public:
    RM_Manager    (PF_Manager &pfm):pfm(pfm){};
    ~RM_Manager   ();

    RC CreateFile (const char *fileName, int recordSize);
    RC DestroyFile(const char *fileName);
    RC OpenFile   (const char *fileName, RM_FileHandle &fileHandle);

    RC CloseFile  (RM_FileHandle &fileHandle);
};

//
// Print-error function
//
void RM_PrintError(RC rc);

#endif
